-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Store resources as components on singleton entities (v2) #21346
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Store resources as components on singleton entities (v2) #21346
Conversation
This reverts commit 8c4269c.
the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ooh, this is exciting! I like the ResourceComponent<R: Resource>
approach! It looks good overall, and most of my comments are style nits.
I think the world_mut()
in the hooks is unsound, though, so we'll need to fix something there.
I'm also curious about the reasons for despawning the whole entity when replacing the resource or in resource_scope
. I had been expecting to preserve the entity and just add and remove the component, but I haven't thought through what the tradeoffs are between the two approaches.
Co-authored-by: Chris Russell <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exciting changes!
|
||
/// Type-erased equivalent of [`Components::valid_resource_id()`]. | ||
#[inline] | ||
#[deprecated( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- If I'm understanding this PR correctly, the behaviour of this function changes? So if I had a code
get_valid_resource_id(resource_type_id)
and upgraded bevy, the function call would start returning unexpected results, correct? In that case, I think it would be better to remove this function completely instead of just deprecating it (users will have to change the code anyways). - If I just have a
TypeId
and don't know the typeR
, is there still some way for me to check if it's registered? (for example, I could get the type IDs from iterating over the wholeTypeRegistry
registrations and checking forReflectResource
type data). If not, one option would be to add these function toReflectResource
.
(the same applies to get_resource_id
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right, but I'll leave it to a clean-up PR. I really want to start wrapping this up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't kept up much with the changes from 0.17, so I did not do a deep dive review for this code. But at a glance, I don't see any major issues with the implementation.
My knowledge here is purely from my experimentation in my own ecs prototypes. At least, I think that's why my review was requested, so I'm reviewing more the concept than the code for now.
Bevy has kind of put itself in a difficult place because we present entities and resources fundamentally differently to users: Res
vs Single
, etc. From my research, an ideal world would have no distinction: a "resource" is just a component where it just so happens that there can only ever be one of them. Then, its some pretty thin utilities over the top, and you're done.
I haven't been following this feature super closely, but from what I can tell, that's not the direction Bevy wants to take–IIUC, mostly for compatibility reasons. That's why we have to make sure resources don't appear in queries, etc. That is, the hard part here is making sure that a resource entity doesn't happen to also have a Transform
component. In my prototype, I see no reason to disallow that, but I can understand the compatibility concerns for Bevy. (Ex: The Bevy way is to have a TargetedEnemy(Option<Entity>)
resource, not a ThisEntityIsTargeted
resource that also lives on the targeted entity.)
So the question is: how do we have it both ways? How can resources be on entities, but not be treated like entities? I think this pr (again, at a glance) does a pretty good job of walking that line.
My only real concern is that this might make it harder to create and use resources that do not correspond to rust types. That might not be an issues, but IIRC, it was supported before, and it's worth mentioning.
But I don't see anything "bad" about this approach in concept, given the compatibility concerns.
Hopefully that all made sense. There's a lot of moving parts here.
If anyone can help me out with sound-ifying the resource component hooks, I'd appreciate it. My last commit made an attempt, but it seems to fail in a pretty unexpected way. |
Co-authored-by: Chris Russell <[email protected]>
This is largely identical to #20934, except we store resource data on a
ResourceComponent<R: Resource>
component on a singleton entity. This has the benefit of sidestepping the annoying double-derive problem of having to both deriveComponent
andResource
for each resource.For more information check out the original PR description #20934.
Closes #20934, #19711, #17485 and is part of #19731.
Other Changes
Deprecate
Components
methodsThis PR deprecates
Components::get_valid_resource_id(type_id: TypeId)
, andComponents::get_resource_id(type_id: TypeId)
. This is because resources (excluding non-send) are not registered with theirTypeId
anymore. Instead they're registered by theTypeId
ofResourceComponent<SomeResource>
. This changes the API as follows:becomes
This becomes confusing, as the method name suggests we're dealing with resources, while in order to use it correctly, we must already be aware that resources are actually hidden behind a component. The same is true for the
get_valid_resource_id
method. Both are being deprecated in favour of eitherresource_id
andvalid_resource_id
for when the type is available, orget_id
orget_valid_id
when it isn't. Using the latter two does require the user to wrap the type inResourceComponent<_>
in order for it to work correctly.Registering a Resource Type
When registering a resource type manually through
app.register_type::<R>()
or through theAppTypeRegistry
, a user must wrap the type inResourceComponent<R>
in order for it to be properly registered.However, when using the untyped API's like
get_resource_by_id
, the user can simplyread::<R>()
sinceResourceComponent<_>
is transparent.Resources implement
MapEntities
by defaultIn order to have
MapEntities
working with resources,#[derive(Resource)]
now automatically implementsMapEntities
. This makes it such thatno longer compiles. Instead write: